#include "spectrumview.h"
#include <QtXml>

SpectrumView::SpectrumView(const QColor& color, QWidget* parent = NULL): QWidget(parent), spectrum(new PreciseSpectrum()) {
    QLayout* layout = new QVBoxLayout(this);
    firstCollector = new QwtPlot();
    firstCollector->setTitle("First collector");
    secondCollector = new QwtPlot();
    secondCollector->setTitle("Second collector");
    setBackgroundColor(color);

    layout->addWidget(firstCollector);
    layout->addWidget(secondCollector);

    setMinimumSize(640, 480);
    setLayout(layout);
}

bool SpectrumView::loadFile(const QString& fileName) {
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot read spectrum %1:\n%2.").arg(fileName).arg(file.errorString()));
        return false;
    }
    QDomDocument doc;
    if (!doc.setContent(&file)) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot read spectrum %1:\n.Wrong xml content.").arg(fileName));
        return false;
    }
    QDomElement domElement = doc.documentElement();

    QApplication::setOverrideCursor(Qt::WaitCursor);
    bool res = spectrum->deserialize(domElement);
    QApplication::restoreOverrideCursor();

    if (!res) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot read spectrum %1:\n.Wrong data.").arg(fileName));
        return false;
    }

    for (int i = 0; i < spectrum->length(); ++i) {
        if (spectrum->at(i)->PEDreference()->collector()) {
            spectrum->at(i)->attach(firstCollector);
        } else {
            spectrum->at(i)->attach(secondCollector);
        }
    }

    setCurrentFile(fileName);

    return true;
}

bool SpectrumView::saveAs() {
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save Precise Spectrum"), curFile, tr("Precise spectrum files (*.psf)"));
    if (fileName.isEmpty()) {
        return false;
    }

    return saveFile(fileName);
}

bool SpectrumView::saveFile(const QString& fileName) {
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly)) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString()));
        return false;
    }

    QTextStream out(&file);
    QApplication::setOverrideCursor(Qt::WaitCursor);
    bool res = serialize(out);
    QApplication::restoreOverrideCursor();

    file.close();

    if (!res) {
        QMessageBox::warning(this, tr("Flavor"), tr("Serialization error emerged during write of %1.").arg(fileName));
        return false;
    }
    setCurrentFile(fileName);
    return true;
}

void SpectrumView::toPdf() {
    QString fileName = QFileDialog::getSaveFileName(this, "Save", "*.pdf");
    if (fileName.isNull()) {
        return;
    }
    QPrinter printer(QPrinter::PrinterResolution);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName(fileName);
    QPainter painter;
    QFile file(fileName);
    file.open(QFile::WriteOnly);
    painter.begin(&printer);

    int indent = 0;
    painter.setFont(QFont("Times", 20, QFont::Bold));
    QString title = QString("%1").arg(curFile);
    painter.drawText(0, indent, title);

    indent += 16;

    QRect rect = QRect(QPoint(0, indent), firstCollector->frameRect().size());
    firstCollector->print(&painter, rect);

    indent += rect.height();

    rect = QRect(QPoint(0, indent), secondCollector->frameRect().size());
    secondCollector->print(&painter, rect);

    file.close();
}

void SpectrumView::copy() {
    QString spectrumAsString;

    QTextStream stream(&spectrumAsString);
    if (!serialize(stream)) {
        return;
    }

    QApplication::clipboard()->setText(spectrumAsString);
    emit copyAvailable(true);
}

void SpectrumView::distract() {
    QString text = QApplication::clipboard()->text();
    QDomDocument doc;
    if (!doc.setContent(text)) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot read spectrum from clipboard:\nWrong xml content."));
        return;
    }
    QDomElement domElement = doc.documentElement();
    QSharedPointer<PreciseSpectrum> spec(new PreciseSpectrum());

    QApplication::setOverrideCursor(Qt::WaitCursor);
    bool res = spec->deserialize(domElement);
    QApplication::restoreOverrideCursor();

    if (!res) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot read spectrum from clipboard:\nWrong data."));
        return;
    }

    res = distract(spec);

    if (!res) {
        //error messages shown earlier
        return;
    }

    documentWasModified();
}

bool SpectrumView::distract(const QSharedPointer<PreciseSpectrum>& spec) {
    if (spec.isNull() || spectrum.isNull()) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot distract spectrum stored in clipboard from current:\nNull data."));
        return false;
    }
    if (!spectrum->commonOptions()->equals(*(spec->commonOptions()))) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot distract spectrum stored in clipboard from current:\nDifferent measure circumstances."));
        return false;
    }

    QApplication::setOverrideCursor(Qt::WaitCursor);
    bool res = spectrum->distract(spec);
    QApplication::restoreOverrideCursor();

    if (!res) {
        QMessageBox::warning(this, tr("Flavor"), tr("Cannot distract spectrum stored in clipboard from current:\nData rows mismatch."));
        return false;
    }
    return true;
}

bool SpectrumView::serialize(QTextStream& destination) const {
    QDomDocument doc;
    doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
    QDomElement root = doc.createElement("control");
    if (!spectrum->serialize(root, doc)) {
        return false;
    }
    doc.appendChild(root);
    destination << doc.toString();
    return true;
}

void SpectrumView::closeEvent(QCloseEvent* event) {
    if (maybeSave()) {
        event->accept();
    } else {
        event->ignore();
    }
}

void SpectrumView::documentWasModified() {
    firstCollector->replot();
    secondCollector->replot();
    setWindowModified(true);
}

bool SpectrumView::maybeSave() {
    if (isWindowModified()) {
        QMessageBox::StandardButton ret;
        ret = QMessageBox::warning(this, tr("Flavor"), tr("'%1' has been modified.\nDo you want to save your changes?").arg(userFriendlyCurrentFile()),
                                   QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        if (ret == QMessageBox::Save) {
            return saveAs();
        } else if (ret == QMessageBox::Cancel) {
            return false;
        }
    }
    return true;
}

void SpectrumView::setCurrentFile(const QString &fileName) {
    curFile = QFileInfo(fileName).canonicalFilePath();
    isUntitled = false;
    setWindowModified(false);
    setWindowTitle(userFriendlyCurrentFile() + "[*]");
}

QString SpectrumView::strippedName(const QString& fullFileName) const {
    return QFileInfo(fullFileName).fileName();
}

void SpectrumView::setBackgroundColor(const QColor& color) {
    firstCollector->setCanvasBackground(color);
    secondCollector->setCanvasBackground(color);
    firstCollector->replot();
    secondCollector->replot();
}
